package completeFuture;

import org.junit.Test;

import java.util.concurrent.CompletableFuture;

public class CompletableFutureTest {

    @Test
    public void supplyAsync() {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("后台执行开始。。。");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "后台执行5秒完成";
        });

        System.out.println("主线程继续执行");
        System.out.println(future.join());
    }

    @Test
    public void runAsync() {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            System.out.println("后台执行开始。。。");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("后台执行5秒完成");
        });

        System.out.println("主线程继续执行");
        future.join();
        System.out.println("后台线程执行完毕");
    }

    /**
     * 链式处理，把上一环节的处理结果继续处理，并在返回一个Future给后面环节
     */
    @Test
    public void thenCompose() {
        CompletableFuture.supplyAsync(() -> 1)
                .thenCompose(value -> CompletableFuture.supplyAsync(() -> value))
                .thenAccept(System.out::println);
    }

    /**
     * 链式处理，把上一环节的处理结果继续处理，并在返回一个Future给后面环节
     */
    @Test
    public void thenApply() {
        CompletableFuture.supplyAsync(() -> 1) //开启一个线程执行
                .thenApply(value -> value + 1) //利用开启的线程继续执行
                .thenApply(value -> value * value) //利用开启的线程继续执行
                .whenComplete((value, exception) -> System.out.println(value)); //执行完成回调事件
    }

    /**
     * 链式处理，消费前一环节的输出
     */
    @Test
    public void thenAccept() {
        CompletableFuture.supplyAsync(() -> 1)
                .thenAccept(System.out::println);
    }

    /**
     * 链式处理，但是不关心前一环节的输出
     */
    @Test
    public void thenRun() {
        CompletableFuture.supplyAsync(() -> 1)
                .thenRun(() -> System.out.println("执行完毕"));
    }

    /**
     * 组合两个future
     */
    @Test
    public void thenCombine() {

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 10);

        CompletableFuture.supplyAsync(() -> 1)
                .thenCombine(future, (a, b) -> a + b)
                .thenAccept(System.out::println);
    }

    /**
     * 执行完成的回调事件
     */
    @Test
    public void whenComplete() {
        CompletableFuture.supplyAsync(() -> "hello world!")
                .whenComplete((ret, ex) -> System.out.println(ret));
    }

    /**
     * 等待全部future处理完
     */
    @Test
    public void allOf() {
        System.out.println("等待后台线程执行完毕。。。");
        CompletableFuture future1 = CompletableFuture.runAsync(() -> {
            System.out.println("线程1开始执行。。。");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程1执行完毕!");
        });

        CompletableFuture future2 = CompletableFuture.runAsync(() -> {
            System.out.println("线程2开始执行。。。");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程2执行完毕!");
        });

        CompletableFuture.allOf(future1, future2).join();
        System.out.println("后台线程全部执行完毕！");
    }

    /**
     * 等待任意一个future处理完
     */
    @Test
    public void anyOf() {
        System.out.println("等待后台线程执行完毕。。。");

        CompletableFuture future1 = CompletableFuture.runAsync(() -> {
            System.out.println("线程1开始执行。。。");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程1执行完毕!");
        });

        CompletableFuture future2 = CompletableFuture.runAsync(() -> {
            System.out.println("线程2开始执行。。。");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程2执行完毕!");
        });

        CompletableFuture.anyOf(future1, future2).join();
        System.out.println("已有一个线程执行完毕！");
    }
}
